//
// Created by 王乐 on 2022/2/17.
//

#include "LePostProcessingRenderer.h"
#include "glad/glad.h"

#include "LeVBOManager.h"

#include "LeCameraManager.h"
#include "LeScreenSettings.h"

#include <iostream>

#include "LeInput.h"

LePostProcessingRenderer::LePostProcessingRenderer()
{}

LePostProcessingRenderer::~LePostProcessingRenderer()
{

}

void LePostProcessingRenderer::preLoopRender()
{
    unsigned int VBO;
    LeVBOManager::findVBO("ScreenQuad", VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));

    m_Shader.useShader();
    m_Shader.setInt("screenTexture", 0);

    // framebuffer configuration
    // -------------------------
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    // create a color attachment texture
    glGenTextures(1, &textureColorbuffer);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
//    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH*2, SCR_HEIGHT*2, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH*2, SCR_HEIGHT*2, 0, GL_RGB, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);

    // create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH*2, SCR_HEIGHT*2); // use a single renderbuffer object for both a depth AND stencil buffer.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it

    // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    dExposure = 1.0f;
}

void LePostProcessingRenderer::postprocessingSetup()
{
    // render
    // ------
    // bind to framebuffer and draw scene as we normally would to color texture
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
}

void LePostProcessingRenderer::render()
{
//    // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
//    glBindFramebuffer(GL_FRAMEBUFFER, 0);
//    glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
//    // clear all relevant buffers
//    glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // set clear color to white (not really necessary actually, since we won't be able to see behind the quad anyways)
//    glClear(GL_COLOR_BUFFER_BIT);
//
//    m_Shader.useShader();
//
//
//    if(LeInput::getKey(GLFW_KEY_1) == GLFW_PRESS)
//        dExposure = 0.1f;
//    if(LeInput::getKey(GLFW_KEY_2) == GLFW_PRESS)
//        dExposure = 1.0f;
//    if(LeInput::getKey(GLFW_KEY_3) == GLFW_PRESS)
//        dExposure = 5.0f;
//
//
//    m_Shader.setFloat("exposure", dExposure);
//
//    glBindVertexArray(VAO);
//    glActiveTexture(GL_TEXTURE0);
//    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);	// use the color attachment texture as the texture of the quad plane
//    glDrawArrays(GL_TRIANGLES, 0, 6);

}

void LePostProcessingRenderer::postLoopRender()
{
    glDeleteFramebuffers(1, &framebuffer);
}

void LePostProcessingRenderer::postprocessingRender()
{
    // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
    // clear all relevant buffers
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // set clear color to white (not really necessary actually, since we won't be able to see behind the quad anyways)
    glClear(GL_COLOR_BUFFER_BIT);

    m_Shader.useShader();


    if(LeInput::getKey(GLFW_KEY_1) == GLFW_PRESS)
        dExposure = 0.1f;
    if(LeInput::getKey(GLFW_KEY_2) == GLFW_PRESS)
        dExposure = 1.0f;
    if(LeInput::getKey(GLFW_KEY_3) == GLFW_PRESS)
        dExposure = 5.0f;


    m_Shader.setFloat("exposure", dExposure);

    glBindVertexArray(VAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);	// use the color attachment texture as the texture of the quad plane
    glDrawArrays(GL_TRIANGLES, 0, 6);
}
